home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / src / bindlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-05  |  40.1 KB  |  1,499 lines

  1. /* @(#)src/bindlib.c    1.16 9/5/92 22:16:42 */
  2.  
  3. /*
  4.  *    Copyright (C) 1992  Ronald S. Karr
  5.  *
  6.  * See the file COPYING, distributed with smail, for restriction
  7.  * and warranty information.
  8.  */
  9.  
  10. /*
  11.  * bindlib.c
  12.  *    common code for the BIND router and the "tcpsmtp" transport,
  13.  *    both of which can the Domain Name Service as implemented
  14.  *    (typically) by the a Berkeley Internet Name Domain (BIND)
  15.  *    server.
  16.  *
  17.  *    bind code converted to general library by Chip Salzenberg.
  18.  */
  19.  
  20. /*
  21.  * Specifications for the bind router and/or tcpsmtp transport:
  22.  *
  23.  *    associated transports:
  24.  *        Generally used with an smtp transport.
  25.  *
  26.  *    private attribute data:
  27.  *        ignore_domains: domains to ignore.  Names under any of these
  28.  *        domains will never be matched.  This prevents expensive
  29.  *        lookups for domains that are known not to be in the DNS.
  30.  *
  31.  *    private attribute flags:
  32.  *        defer_no_connect:  if set and we cannot connect to the
  33.  *        name server, try again later.  This is set by default.
  34.  *        local_mx_okay: if not set, an MX record which points to the
  35.  *        local host is considered to be an error which will
  36.  *        will cause mail to be returned to the sender.
  37.  *        defnames:  append a default domain to an unqualified hostname,
  38.  *        using the RES_DEFNAME flag to the resolver library.
  39.  *        This is set by default.
  40.  *        domain_required:  at least two name components are required
  41.  *        in the hostname.  Setting this prevents lookups of
  42.  *        single-component names which are unlikely to be valid
  43.  *        hosts in the DNS.
  44.  *        mx_only:  use only MX records in matching an address.  If a
  45.  *        host doesn't have a MX records, then don't use the A
  46.  *        or WKS records for routing.
  47.  *
  48.  *    algorithm:
  49.  *        For bind routing, given a target use the following
  50.  *        strategy:
  51.  *
  52.  *        1.  Replace sequences of more than one dot in the target
  53.  *        with a single dot.  Remove any dots from the beginning
  54.  *        and end of the target.
  55.  *
  56.  *        2.    See if there is an MX record for the target.  If so,
  57.  *        skip to step 6.
  58.  *
  59.  *        3.    If the MX record query returned a CNAME record, then
  60.  *        treat the canonical name as the target and return to
  61.  *        step 2.
  62.  *
  63.  *        4.  Do not match the target.
  64.  *
  65.  *        5.  If the primary name of the local host is listed in an
  66.  *        MX record, all MX record's with equal or greater
  67.  *        preference fields are discarded.
  68.  *
  69.  *        6.  If the only MX record remaining references the local
  70.  *        host, do not match the target.
  71.  *
  72.  *        7.  Choose one of the MX records with the lowest
  73.  *        preference fields.  Match the address with the
  74.  *        next_host value set to the referenced host.
  75.  *
  76.  *          The algorithm is extended for the UK domain by (1)
  77.  *          checking a list of top-level domains and converting the
  78.  *          target to a gateway name if matched, (2) discarding any MX
  79.  *          records which match the uk_ignore_gateways parameter, or
  80.  *          whose preference value is greater than uk_max_precedence,
  81.  *          (3) re-trying with the list of widening strings and then
  82.  *          trying the address inverted before giving up, and (4)
  83.  *          matching with the greybook transport if if MX records were
  84.  *          found but were all discarded by the above rules.
  85.  *
  86.  *        When a hostname is matched, the next_host field is set to
  87.  *        the referenced host, for MX records, or the matched host
  88.  *        for A records.  The route field is set to the canonical
  89.  *        name for the host, if that is different from the original
  90.  *        target host.  The match length is always set to the length
  91.  *        of the original target host.
  92.  *
  93.  * NOTE:  Use of WKS records is enabled if the USE_WKS_RECORDS macro
  94.  *      is defined.  This can be set from the EDITME file with the
  95.  *      MISC_H_DEFINES variable.  If this macro is not defined, then
  96.  *      WKS records are not retrieved and are assumed to exist and
  97.  *      to contain the SMTP service.
  98.  */
  99.  
  100. #define NEED_SOCKETS
  101. #include <stdio.h>
  102. #include <sys/types.h>
  103. #include <sys/stat.h>
  104. #include <sys/param.h>
  105. #include "defs.h"
  106.  
  107. /*
  108.  * Compilation of this entire file depends on "HAVE_BIND".
  109.  */
  110.  
  111. #ifdef HAVE_BIND
  112.  
  113. #include "smail.h"
  114. #include "addr.h"
  115. #include "route.h"
  116. #include "transport.h"
  117. #include "bindlib.h"
  118. #include "bindsmtpth.h"
  119. #include "lookup.h"
  120. #include "dys.h"
  121. #ifndef DEPEND
  122. # include "extern.h"
  123. # include "debug.h"
  124. # include "error.h"
  125. #endif
  126.  
  127. #if PACKETSZ > 1024
  128. # define MAXPACKET    PACKETSZ
  129. #else
  130. # define MAXPACKET    1024
  131. #endif
  132.  
  133. #ifndef GETSHORT
  134. /*
  135.  * earlier versions of bind don't seem to define these useful macros,
  136.  * so roll our own.
  137.  */
  138. # define GETSHORT(i, p)    \
  139.     ((i)  = ((unsigned)(*(p)++ & 0xff) << 8),    \
  140.      (i) |= ((unsigned)(*(p)++ & 0xff)))
  141. # define GETLONG(l, p)    \
  142.     ((l)  = ((unsigned long)(*(p)++ & 0xff) << 24),    \
  143.      (l) |= ((unsigned long)(*(p)++ & 0xff) << 16),    \
  144.      (l) |= ((unsigned long)(*(p)++ & 0xff) << 8),    \
  145.      (l) |= ((unsigned long)(*(p)++ & 0xff)))
  146. # define PUTSHORT(i, p)    \
  147.     ((*(p)++ = (unsigned)(i) >> 8),            \
  148.      (*(p)++ = (unsigned)(i)))
  149. # define PUTLONG(l, p)    \
  150.     ((*(p)++ = (unsigned long)(l) >> 24),        \
  151.      (*(p)++ = (unsigned long)(l) >> 16),        \
  152.      (*(p)++ = (unsigned long)(l) >> 8),        \
  153.      (*(p)++ = (unsigned long)(l)))
  154. #endif
  155.  
  156. /*
  157.  * The standard rrec structure doesn't have a space for the domain
  158.  * name, so define our own.
  159.  */
  160. enum rr_sect { SECT_AN, SECT_NS, SECT_AR };
  161. typedef struct rr {
  162.     enum rr_sect rr_sect;        /* resource record section */
  163.     char  *rr_dname;            /* domain name */
  164.     short  rr_class;            /* class number */
  165.     short  rr_type;            /* type number */
  166.     int    rr_size;            /* size of data area */
  167.     char  *rr_data;            /* pointer to data */
  168. } RR;
  169.  
  170. /* structure for iterating over RR's with getnextrr() */
  171. struct rr_iterator {
  172.     RR rr;                /* space for storing RR */
  173.     char dname[MAXDNAME];        /* space for storing domain name */
  174.     char *dp;                /* pointer within packet */
  175.     HEADER *hp;                /* saved header pointer */
  176.     char *eom;                /* end of packet */
  177.     int ancount;            /* count of answer records */
  178.     int nscount;            /* count of ns records */
  179.     int arcount;            /* count of additional records */
  180. };
  181.  
  182. /*
  183.  * import h_errno; many systems don't define it in <netdb.h>
  184.  */
  185.  
  186. #ifndef OBSOLETE_RESOLVER
  187. extern int h_errno;
  188. #endif
  189.  
  190. /* functions local to this file */
  191.  
  192. #ifdef ANSI_C
  193. # define P_(x) x
  194. #else
  195. # define P_(x) ()
  196. #endif
  197.  
  198. static int bind_addr_work P_((char*,long,struct bindlib_private*,char*,
  199.                   struct rt_info*,struct error **));
  200. static char *strip_dots P_((char*));
  201. static void flip P_((char *));   /* Flip address between UK/world order */
  202. static char *rewrite_header P_((char *, char *, char *));
  203. static int get_records P_((char*,int,HEADER*,int*,char **));
  204. static RR *getnextrr P_((struct rr_iterator*,int));
  205. static void rewindrr P_((struct rr_iterator*,HEADER*,int));
  206. static int find_a_records P_((struct mx_transport_hint*,char*,char **));
  207. static struct error *lost_server P_((char*));
  208. static struct error *server_failure P_((char*,char*));
  209. static struct error *packet_error P_((char*,char*,char*));
  210. static struct error *no_valid_mx_records P_((char*,char*));
  211. static struct error *matched_local_host P_((char*,char*));
  212. static struct error *no_transport_error P_((char*,char*));
  213. static int decode_mx_rr P_((RR*,struct rr_iterator*,char **,int*));
  214. static struct transport_hints * new_mx_hint P_((int,char*,int));
  215. static void add_mx_hint P_((struct transport_hints **,int,char*,int));
  216. static void free_mx_hint P_((struct transport_hints **));
  217. static void add_a_hint P_((struct mx_transport_hint*,char*,char*));
  218.  
  219. /*
  220.  * bind_addr - lookup a host through the domain system
  221.  *
  222.  * Use the algorithm described at the top of this source file for
  223.  * finding a match for a target.
  224.  *
  225.  * Return one of the following values:
  226.  *
  227.  * These return codes apply only to the specific address:
  228.  *    DB_SUCCEED    Matched the target host.
  229.  *    DB_NOMATCH    Did not match the target host.
  230.  *    DB_FAIL        Fail the address with the given error.
  231.  *    DB_AGAIN    Try to route with this address again at a
  232.  *            later time.
  233.  *
  234.  * These return codes apply to this router in general:
  235.  *    FILE_NOMATCH    There is no server running on this machine.
  236.  *    FILE_AGAIN    Lost contact with server, or server is
  237.  *            required to exist.  Try again later.
  238.  *    FILE_FAIL    A major error has been caught in router,
  239.  *            notify postmaster.
  240.  */
  241.  
  242. int
  243. bind_addr(raw_target, flags, priv, what, rt_info, error_p)
  244.     char *raw_target;            /* raw target address */
  245.     long flags;                /* bind-specific flags */
  246.     struct bindlib_private *priv;    /* bind-specific data */
  247.     char *what;                /* who called, for messages */
  248.     struct rt_info *rt_info;        /* return route info here */
  249.     struct error **error_p;        /* return lookup error here */
  250. {
  251.     long save_res_options;        /* like _res.options in <resolv.h> */
  252.     int ret;
  253.  
  254.     save_res_options = _res.options;
  255.     ret = bind_addr_work(raw_target, flags, priv, what, rt_info, error_p);
  256.     _res.options = save_res_options;
  257.  
  258.     return ret;
  259. }
  260.  
  261. static int
  262. bind_addr_work(raw_target, flags, priv, what, rt_info, error_p)
  263.     char *raw_target;            /* raw target address */
  264.     long flags;                /* bind-specific flags */
  265.     struct bindlib_private *priv;    /* bind-specific data */
  266.     char *what;                /* who called, for messages */
  267.     struct rt_info *rt_info;        /* return route info here */
  268.     struct error **error_p;        /* return lookup error here */
  269. {
  270.     char *target;            /* raw_target stripped of extra dots */
  271.     static char *orig_target = NULL;    /* original dot-stripped target */
  272.     static char *full_target = NULL;    /* target sent by res_send */
  273.     HEADER *mx_rrs = NULL;        /* response for MX rr's */
  274.     int mx_size;            /* size of MX rr response packet */
  275.     struct rr_iterator mx_it;        /* MX rr iterator */
  276.     struct rr_iterator a_it;        /* A rr iterator */
  277.     RR *mx_rr;                /* a single MX rr */
  278.     RR *a_rr;                /* a single A rr */
  279.     static int no_server = FALSE;    /* TRUE if no server process */
  280.     static int found_server = FALSE;    /* TRUE if server process found */
  281.     int success;            /* value to return */
  282.     char *error;            /* error text from called function */
  283.     int widencount = 0;                 /* number of times widened */
  284.     int inverting = FALSE;              /* trying inverted address */
  285.     int gated = FALSE;                  /* routed via a gateway */
  286.     int UK_MX_rejected = FALSE;         /* at least one MX was rejected */
  287.     int local_precedence = -1;        /* precedence of MX to local host */
  288.     struct transport_hints *mx_hints = 0, **mx_a;
  289.     struct transport_hints *hint;
  290.  
  291.     /*
  292.      * memory management notes:
  293.      *   target        points to static area returned by strip_dots().
  294.      *            do not free.
  295.      *   orig_target    static pointer of convenience.  do not free.
  296.      *   full_target    static pointer of convenience.  do not free.
  297.      */
  298.  
  299.     if (no_server) {
  300.     return DB_NOMATCH;
  301.     }
  302.  
  303.     /*
  304.      * strip extra dots from the target to ensure sane lookups.
  305.      * If the target contained any dots before being stripped,
  306.      * then don't allow the resolver to add the default domain.
  307.      * This allows mail to high-level domains (e.g., "com.")
  308.      * while also allowing use of default domain suffixes.
  309.      */
  310.  
  311. #ifdef RES_DEFNAMES
  312. # ifndef RES_DNSRCH
  313. # define RES_DNSRCH    0
  314. # endif
  315.     if (flags & BIND_DEFNAMES && strchr(raw_target, '.') == NULL) {
  316.     _res.options |= RES_DEFNAMES|RES_DNSRCH;
  317.     } else {
  318.     _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
  319.     }
  320. #endif
  321.  
  322.     /*
  323.      * Step 1: Omit needless dots!
  324.      */
  325.  
  326.     target = strip_dots(raw_target);
  327.  
  328.     if (orig_target) {
  329.     xfree(orig_target);
  330.     }
  331.     orig_target = COPY_STRING(target);
  332.  
  333.     if (full_target) {
  334.     xfree(full_target);
  335.     }
  336.     full_target = NULL;
  337.  
  338.     /*
  339.      * if the target is in one of the "ignore" domains, then don't
  340.      * match it.  This prevents expensive lookups of domains that are
  341.      * known not to exist in the DNS, such as .uucp or .bitnet.
  342.      */
  343.  
  344.     if (priv->ignore_domains) {
  345.     if (match_end_domain(priv->ignore_domains, target) != NULL) {
  346.         return DB_NOMATCH;
  347.     }
  348.     }
  349.  
  350.     if (debug >= DBG_DRIVER_HI) {
  351.     _res.options |= RES_DEBUG;    /* turn on resolver debugging */
  352.     }
  353.  
  354.     /*
  355.      * first see if the address matches one of the list of special
  356.      * gateways.  if so, change the target to the gateway, and set
  357.      * the full_target to the original string so it will be passed
  358.      * on to the gateway.  the flag prevents subsequent updating of
  359.      * full_target from the DNS records.
  360.      */
  361.  
  362.     if (priv->gateways) {
  363.     char *cur;
  364.     char *gateway = NULL;
  365.  
  366.     for (cur = strcolon(priv->gateways);
  367.          cur && !gated;
  368.          cur = strcolon((char *)NULL))
  369.     {
  370.         if (!gateway) {
  371.         gateway = COPY_STRING(cur);
  372.         }
  373.         else if (EQ(cur, "+")) {
  374.         if (gateway) {
  375.             xfree(gateway);
  376.         }
  377.         gateway = NULL;
  378.         }
  379.         else if (is_suffix(cur, target, FALSE)) {
  380.         full_target = COPY_STRING(target);
  381.         target = strip_dots(gateway);
  382.         gated = TRUE;
  383.         }
  384.     }
  385.  
  386.     if (gateway) {
  387.         xfree(gateway);
  388.     }
  389.     }
  390.  
  391.     /* store return values for common case */
  392.     rt_info->next_host = COPY_STRING(target);
  393.     rt_info->route = NULL;
  394.     rt_info->matchlen = strlen(raw_target);
  395.  
  396.     /*
  397.      * if the domain_required flag is set, then the target hostname
  398.      * is required to have at least one "."
  399.      */
  400.  
  401.     if (flags & BIND_DOMAIN_REQUIRED && strchr(target, '.') == NULL) {
  402.     return DB_NOMATCH;
  403.     }
  404.  
  405. get_target_mx_records:
  406.  
  407.     DEBUG1(DBG_ROUTE_LO, "Trying %s\n", target);
  408.  
  409.     /* Step 2:  See if there are any MX records */
  410.     if (mx_rrs == NULL) {
  411.     mx_rrs = (HEADER *)xmalloc(MAXPACKET);
  412.     }
  413.  
  414.     success = get_records(target, T_MX, mx_rrs, &mx_size, &error);
  415.     if ((success == DB_NOMATCH) && !(flags & BIND_MX_ONLY))
  416.     success = get_records(target, T_ANY, mx_rrs, &mx_size, &error);
  417.  
  418.     if (success != DB_SUCCEED) {
  419.     switch (success) {
  420.  
  421.     case FILE_NOMATCH:
  422.         if (! (flags & BIND_DEFER_NO_CONN) && ! found_server) {
  423.         no_server = TRUE;
  424.         success = DB_NOMATCH;
  425.         break;
  426.         }
  427.         if (found_server) {
  428.         *error_p = lost_server(what);
  429.         } else {
  430.         *error_p =
  431.             server_failure(what, "Connection to BIND server failed");
  432.         }
  433.         success = FILE_AGAIN;
  434.         break;
  435.  
  436.     case DB_AGAIN:
  437.     case DB_FAIL:
  438.     case FILE_AGAIN:
  439.         *error_p = server_failure(what, error);
  440.         break;
  441.  
  442.     case DB_NOMATCH:
  443.  
  444.         /*
  445.          * Before giving up, we try widening the name according to a
  446.          * configured list. Because the strcolon routine re-uses its
  447.          * store, we can't remember the position globally. We just
  448.          * remember the count of widenings. As there will typically be
  449.          * only two or three, don't worry about the inefficiency.
  450.          */
  451.  
  452.         /* Don't do it if gated.  (Shouldn't get here, anyway.) */
  453.         if (!gated) {
  454.         char *w;
  455.         int i;
  456.  
  457.         w = strcolon(priv->widen_domains ? priv->widen_domains : "");
  458.         for (i = 0; i < widencount; i++)
  459.             w = strcolon((char *)NULL);
  460.         if (w && *w)
  461.         {
  462.             struct str new;    /* region for building new string */
  463.  
  464.             STR_INIT(&new);
  465.             STR_CAT(&new, orig_target);
  466.             STR_NEXT(&new, '.');
  467.             STR_CAT(&new, w);
  468.             STR_NEXT(&new, '\0');
  469.             STR_DONE(&new);
  470.  
  471.             target = strip_dots(new.p);
  472.             xfree(rt_info->next_host);
  473.             rt_info->next_host = new.p;
  474.  
  475.             widencount++;
  476.             goto get_target_mx_records;
  477.         }
  478.  
  479.         /*
  480.          * Deal with setting up for flipping addresses; don't do it
  481.          * the address is already in the "uk" domain.
  482.          */
  483.  
  484.         else if ((flags & BIND_UK_TRY_INVERT) && !inverting &&
  485.              !is_suffix("uk", orig_target, TRUE))
  486.         {
  487.             inverting = TRUE;
  488.             flip(orig_target);     /* does it in situ */
  489.  
  490.             target = strip_dots(orig_target);
  491.             xfree(rt_info->next_host);
  492.             rt_info->next_host = COPY_STRING(target);
  493.  
  494.             widencount = 0;
  495.             goto get_target_mx_records;
  496.         }
  497.         }
  498.         break;
  499.     }
  500.  
  501.     xfree((char *)mx_rrs);
  502.     return success;
  503.     }
  504.  
  505.     /* We have connected to the server at least once */
  506.     found_server = TRUE;
  507.  
  508.     /* See if there are any MX records */
  509.     rewindrr(&mx_it, mx_rrs, mx_size);
  510.     while ((mx_rr = getnextrr(&mx_it, FALSE)) && mx_rr->rr_type != T_MX)
  511.     ;
  512.  
  513.     if (mx_rr == NULL) {
  514.  
  515.     /* Step 3:  Look for a CNAME record */
  516.     rewindrr(&mx_it, mx_rrs, mx_size);
  517.     while ((mx_rr = getnextrr(&mx_it, FALSE)) && mx_rr->rr_type != T_CNAME)
  518.         ;
  519.     if (mx_rr) {
  520.         static char nambuf[MAXDNAME];
  521.         int dlen;
  522.  
  523.         dlen = dn_expand((char *)mx_it.hp, mx_it.eom, mx_rr->rr_data,
  524.                  nambuf, MAXDNAME);
  525.         if (dlen < 0) {
  526.         /* format error in response packet */
  527.         *error_p = packet_error(what, "CNAME", target);
  528.  
  529.         xfree((char *)mx_rrs);
  530.         return DB_AGAIN;
  531.         }
  532.         target = nambuf;
  533.         xfree(rt_info->next_host);
  534.         rt_info->next_host = COPY_STRING(target);
  535.  
  536.         /*
  537.          * RFC 974:
  538.          * There is one other special case.  If the response contains
  539.          * an answer which is a CNAME RR, it indicates that REMOTE is
  540.          * actually an alias for some other domain name. The query
  541.          * should be repeated with the canonical domain name.
  542.          */
  543.         /*
  544.          * The next query should really be done with the DEFNAMES flag
  545.          * cleared !!
  546.          */
  547.         goto get_target_mx_records;
  548.     }
  549.  
  550.     if (! (flags & BIND_MX_ONLY)) {
  551.         /*
  552.          * from RFC 974:
  553.          * It is possible that the list of MXs in the response to
  554.          * the query will be empty.  This is a special case.  If the
  555.          * list is empty, mailers should treat it as if it contained
  556.          * one RR, an MX RR with a preference value of 0, and a host
  557.          * name of REMOTE.  (I.e., REMOTE is its only MX).  In
  558.          * addition, the mailer should do no further processing on
  559.          * the list, but should attempt to deliver the message to
  560.          * REMOTE.  The idea here is that if a domain fails to
  561.          * advertise any information about a particular name we will
  562.          * give it the benefit of the doubt and attempt delivery.
  563.          */
  564.         char *fullname;
  565.  
  566.         if (islocalhost(target))
  567.         local_precedence = 0;
  568.         if (_res.options & RES_DEFNAMES &&
  569.         strchr(target, '.') == NULL &&
  570.         _res.defdname[0] != '\0')
  571.         {
  572.         add_mx_hint(&mx_hints, 0,
  573.                 xprintf("%s.%s", target, _res.defdname),
  574.                 TRUE);
  575.         fullname = xprintf("%s.%s", target, _res.defdname);
  576.         } else {
  577.         add_mx_hint(&mx_hints, 0, target, TRUE);
  578.         fullname = COPY_STRING(target);
  579.         }
  580.  
  581.         /*
  582.          * Deal with widening of the target name. This may have been
  583.          * done explicitly above, or it may have been done by the DNS
  584.          * resolver for an unqualified name. We cautiously do this only
  585.          * for UK addresses, but it is probably OK in general, except
  586.          * that it wastes time. Note: do *not* do this for explicitly
  587.          * gatewayed addresses. We have to do this separately for the
  588.          * MX and non-MX cases, as the data comes from different places,
  589.          * in the MX case, aliases may have been followed, etc.
  590.          */
  591.  
  592.         if (!gated && is_suffix("uk", fullname, TRUE)) {
  593.         struct list *q;
  594.  
  595.         for (q = header; q; q = q->succ) {
  596.             if (strncmpic(q->text, "to:", 3) == 0 ||
  597.             strncmpic(q->text, "cc:", 3) == 0)
  598.             {
  599.             q->text = rewrite_header(q->text, raw_target,
  600.                          fullname);
  601.             }
  602.         }
  603.         }
  604.  
  605.         xfree(fullname);
  606.     }
  607.     }
  608.  
  609.     /* mx records received: scan them */
  610.  
  611.     else {
  612.     rewindrr(&mx_it, mx_rrs, mx_size);
  613.     while (mx_rr = getnextrr(&mx_it, FALSE)) {
  614.         if (mx_rr->rr_type == T_MX) {
  615.         char *name;
  616.         int precedence;
  617.  
  618.         success = decode_mx_rr(mx_rr, &mx_it, &name, &precedence);
  619.         if (success != DB_SUCCEED) {
  620.             *error_p = packet_error(what, "MX", target);
  621.             xfree((char *)mx_rrs);
  622.             return DB_AGAIN;
  623.         }
  624.         /*
  625.          * grab the domain returned in the packet as
  626.          * the real target name, unless gatewayed
  627.          */
  628.                 if (!gated) {
  629.             if (full_target) {
  630.             xfree(full_target);
  631.             }
  632.             if (! EQIC(target, mx_it.dname)) {
  633.             full_target = COPY_STRING(mx_it.dname);
  634.             } else {
  635.             full_target = COPY_STRING(target);
  636.             }
  637.                 }
  638.  
  639.         /*
  640.                  * Pick up the local host's precedence.
  641.          */
  642.         if (islocalhost(name)
  643.             && (local_precedence < 0 || precedence < local_precedence))
  644.         {
  645.             local_precedence = precedence;
  646.         }
  647.  
  648.                 /*
  649.          * If the address is in the UK, and is not gated, we must
  650.          * modify the To: and Cc: fields with the widened address.
  651.          */
  652.  
  653.                 if (!gated && is_suffix("uk", mx_it.dname, TRUE))
  654.         {
  655.             struct list *q;
  656.  
  657.             for (q = header; q; q = q->succ) {
  658.             if (strncmpic(q->text, "to:", 3) == 0 ||
  659.                 strncmpic(q->text, "cc:", 3) == 0)
  660.             {
  661.                 q->text = rewrite_header(q->text, raw_target,
  662.                              mx_it.dname);
  663.             }
  664.                     }
  665.         }
  666.  
  667.         /*
  668.          * Use an MX if precedence is within bounds and if
  669.          * it doesn't specify a gateway to be ignored.
  670.          */
  671.  
  672.                 if (is_suffix("uk", mx_it.dname, TRUE) &&
  673.             ((priv->uk_max_precedence > 0 &&
  674.               precedence > priv->uk_max_precedence) ||
  675.              (priv->uk_ignore_gateways &&
  676.               is_string_in_list(name, priv->uk_ignore_gateways))))
  677.         {
  678.             UK_MX_rejected = TRUE;
  679.         }
  680.                 else
  681.         {
  682.             /*
  683.              * This test sometimes avoids adding exchangers that must
  684.              * not be used.
  685.              */
  686.             if (local_precedence < 0 || precedence < local_precedence)
  687.             add_mx_hint(&mx_hints, precedence, name, FALSE);
  688.         }
  689.         }
  690.     }
  691.     }
  692.  
  693.     mx_a = &mx_hints;
  694.     while (*mx_a) {
  695. #define mx_hint ((struct mx_transport_hint *)((*mx_a)->private))
  696.     int precedence = mx_hint->preference;
  697.  
  698.     if (local_precedence >= 0 && precedence >= local_precedence) {
  699.         /*
  700.          * RFC 974:
  701.          * If the domain name LOCAL is listed as an MX RR, all MX
  702.          * RRs with a preference value greater than or equal to that
  703.          * of LOCAL's must be discarded.
  704.          */
  705.         free_mx_hint(mx_a);
  706.         continue;
  707.     }
  708.     mx_a = &(*mx_a)->succ;
  709. #undef mx_hint
  710.     }
  711.  
  712.     /* if there were no valid MX records... */
  713.     if (! mx_hints) {
  714.     xfree((char *)mx_rrs);
  715.  
  716.     if (local_precedence >= 0) {
  717.         if ((flags & BIND_LOCAL_MX_OKAY) == 0) {
  718.         *error_p = matched_local_host(what, target);
  719.         return DB_FAIL;
  720.         }
  721.         return DB_NOMATCH;
  722.     }
  723.  
  724.     /*
  725.      * This is not an error in the UK if MX records were rejected
  726.      * for "UK" reasons (i.e. via the preference value or
  727.      * uk_ignore_gateways.)  In this case, we assume that JANET mail
  728.      * can reach the address, since all sites with this kind of
  729.      * gateway MX record should be accessible via GreyBook mail.
  730.      *
  731.      * A configuration option specifies whether this system has a
  732.      * greybook transport or not. If not, just yield NOMATCH,
  733.      * assuming a smarthost driver will pick up the address.
  734.      */
  735.  
  736.         if (UK_MX_rejected)
  737.     {
  738.         struct transport *tp;
  739.  
  740.         if (priv->uk_greybook_transport == NULL)
  741.         return DB_NOMATCH;
  742.  
  743.         rt_info->transport = find_transport(priv->uk_greybook_transport);
  744.         rt_info->route = full_target;
  745.         full_target = NULL;
  746.  
  747.         if (!rt_info->transport) {
  748.         *error_p = no_transport_error(what,
  749.                           priv->uk_greybook_transport);
  750.         return DB_NOMATCH;
  751.         }
  752.  
  753.         /*
  754.          * Ensure that the target and the route are in UK order,
  755.          * unless the option is set to suppress this (future hope!)
  756.          */
  757.         if (!(flags & BIND_UK_GREY_WORLD))
  758.         {
  759.         if (is_suffix("uk", rt_info->route, TRUE))
  760.             flip(rt_info->route);
  761.         if (is_suffix("uk", rt_info->next_host, TRUE))
  762.             flip(rt_info->next_host);
  763.         }
  764.         return DB_SUCCEED;
  765.     }
  766.  
  767.     /* it was an error, after all */
  768.     if (!(flags & BIND_MX_ONLY)) {
  769.         *error_p = no_valid_mx_records(what, target);
  770.     }
  771.     return DB_NOMATCH;
  772.     }
  773.  
  774.     /*
  775.      * if any MX record points to a different host than the target,
  776.      * make sure the target hostname is passed to that host.
  777.      */
  778.     if (full_target) {
  779.     for (hint = mx_hints; hint; hint = hint->succ) {
  780.         if (EQIC(hint->hint_name, "mx")) {
  781. #define mx_hint ((struct mx_transport_hint *)(hint->private))
  782.         if (! EQIC(mx_hint->exchanger, full_target)) {
  783.             rt_info->route = full_target;
  784.             full_target = NULL;
  785.             break;
  786.         }
  787.         }
  788.     }
  789.     }
  790.  
  791.     /* look for relevant A records in the additional section of the MX answer */
  792.     rewindrr(&a_it, mx_rrs, mx_size);
  793.     while ((a_rr = getnextrr(&a_it, TRUE))!=0) {
  794.     if (a_rr->rr_type==T_A) {
  795.         for (hint = mx_hints; hint; hint = hint->succ) {
  796. #define mx_hint ((struct mx_transport_hint *)(hint->private))
  797.         if (EQIC(mx_hint->exchanger, a_it.dname))
  798.             add_a_hint(mx_hint, a_it.dname, a_rr->rr_data);
  799. #undef mx_hint
  800.         }
  801.     }
  802.     }
  803.  
  804.     xfree((char *)mx_rrs);
  805.     mx_a = &mx_hints;
  806.     while (*mx_a) {
  807. #define mx_hint ((struct mx_transport_hint *)((*mx_a)->private))
  808.     if (! mx_hint->ipaddrs) {
  809.         /* Go out and get an A record */
  810.         success = find_a_records(mx_hint, mx_hint->exchanger, &error);
  811.         switch (success) {
  812.  
  813.         case DB_SUCCEED:
  814.         mx_a = &(*mx_a)->succ;
  815.         break;
  816.  
  817.         case DB_NOMATCH:
  818.         if (! mx_hint->implicit)
  819.             /* This is an error! */;
  820.         free_mx_hint(mx_a);
  821.         break;
  822.  
  823.         case FILE_NOMATCH:
  824.         success = FILE_AGAIN;
  825.         /* FALL THROUGH */
  826.  
  827.         case DB_FAIL:
  828.         case DB_AGAIN:
  829.         case FILE_AGAIN:
  830.         /* Step 5:  Do not match the target */
  831.         *error_p = server_failure(what, error);
  832.         return success;
  833.         }
  834.     } else {
  835.         mx_a = &(*mx_a)->succ;
  836.     }
  837. #undef mx_hint
  838.     }
  839.  
  840.     if (mx_hints) {
  841.     rt_info->tphint_list = mx_hints;
  842.     return DB_SUCCEED;
  843.     } else {
  844.     return DB_NOMATCH;
  845.     }
  846. }
  847.  
  848. /*
  849.  * strip_dots - remove extra dots from a hostname string
  850.  *
  851.  * Remove all dots from the beginning and end of a string.  Also, any
  852.  * sequence of more than one dot is replaced by a single dot.  For
  853.  * example, the string:
  854.  *
  855.  *    .att..com.
  856.  *
  857.  * will result in the string:
  858.  *
  859.  *    att.com
  860.  *
  861.  * The operation is non-destructive on the passed string.  The
  862.  * resulting value points to a region which may be reused on
  863.  * subsequent calls to strip_dots().
  864.  */
  865. static char *
  866. strip_dots(s)
  867.     register char *s;
  868. {
  869.     static struct str new;        /* region for building new string */
  870.     static int inited = FALSE;        /* true if target initialized */
  871.  
  872.     /* initialize or clear the new string */
  873.     if (! inited) {
  874.     STR_INIT(&new);
  875.     } else {
  876.     new.i = 0;
  877.     }
  878.  
  879.     /*
  880.      * copy target, removing extra dots.
  881.      */
  882.     while (*s == '.') s++;
  883.     do {
  884.     if (*s == '.') {
  885.         while (*s == '.') s++;
  886.         if (*s) --s;
  887.     }
  888.     STR_NEXT(&new, *s);
  889.     } while (*s++);
  890.  
  891.     return new.p;
  892. }
  893.  
  894. /*
  895.  * flip - flip address between UK/world order
  896.  *
  897.  * operates on the string in situ
  898.  */
  899. static void
  900. flip(s)
  901.     char *s;
  902. {
  903.     static struct str new;        /* region for building new string */
  904.     static int inited = FALSE;        /* true if target initialized */
  905.     char *p;
  906.  
  907.     /* initialize or clear the new string */
  908.     if (! inited) {
  909.     STR_INIT(&new);
  910.     } else {
  911.     new.i = 0;
  912.     }
  913.  
  914.     p = s + strlen(s);
  915.     while (p > s) {
  916.     if (*--p == '.') {
  917.         *p = '\0';
  918.         if (*(p + 1)) {
  919.         STR_CAT(&new, p + 1);
  920.         if (p > s) {
  921.             STR_NEXT(&new, '.');
  922.         }
  923.         }
  924.     }
  925.     }
  926.     STR_CAT(&new, s);
  927.     strcpy(s, new.p);
  928. }
  929.  
  930. /*
  931.  * rewrite-header - re-write an address in a header to be the
  932.  * correct UK address, possibly widened and/or re-ordered from
  933.  * what the user typed. Used for To: and Cc: fields.
  934.  *
  935.  * Under some circumstances smail seems to go round the loop
  936.  * twice, so be careful not to do the job twice.
  937.  */
  938.  
  939. static char *
  940. rewrite_header(text, oldtarget, newtarget)
  941.     char *text;
  942.     char *oldtarget;
  943.     char *newtarget;
  944. {
  945.     char *p = text;
  946.     int oldlen = strlen(oldtarget);
  947.     int newlen = strlen(newtarget);
  948.  
  949.     while (*p)
  950.     {
  951.     while (*p != 0 && *p != '@')
  952.         p++;
  953.     if (*p == 0)
  954.         break;
  955.  
  956.     if (strncmpic(++p, oldtarget, oldlen) == 0)
  957.     {
  958.         int c = p[oldlen];
  959.         if (c == 0 || c == ',' || c == '>' ||
  960.         c == ' ' || c == '\n' || c == '\t')
  961.         {
  962.         if (oldlen == newlen)
  963.             memcpy(p, newtarget, newlen);
  964.         else
  965.         {
  966.             int baselen = p - text;
  967.             int oldtextlen = strlen(text);
  968.             char *newtext = xmalloc(oldtextlen+1+(newlen-oldlen));
  969.             memcpy(newtext, text, baselen);
  970.             memcpy(newtext+baselen, newtarget, newlen);
  971.             memcpy(newtext+baselen+newlen, p+oldlen,
  972.                oldtextlen-baselen-oldlen+1);
  973.             xfree(text);
  974.             text = newtext;
  975.             p = text + baselen + newlen;
  976.         }
  977.         }
  978.     }
  979.     }
  980.  
  981.     return text;
  982. }
  983.  
  984.  
  985. /*
  986.  * get_records - query the domain system for resource records of the given
  987.  *         name.
  988.  *
  989.  * Send out a query and return the response packet in a passed buffer.
  990.  * Resource records are in the bytes following the header for that
  991.  * packet.  The actual size of the response packet is stored in pack_size.
  992.  *
  993.  * The passed answer buffer must have space for at least MAXPACKET
  994.  * bytes of data.
  995.  *
  996.  * Return one of the following response codes:
  997.  *
  998.  *    DB_SUCCEED    We received an affirmative packet from the
  999.  *            server.
  1000.  *    DB_NOMATCH    We received a negative response from the server
  1001.  *            indicating that the name does not exist.
  1002.  *    DB_FAIL        We received a negative response from the
  1003.  *            server indicating some problem with the
  1004.  *            packet.
  1005.  *    DB_AGAIN    We received a negative response from the
  1006.  *            server indicating a temporary failure while
  1007.  *            processing the name.
  1008.  *    FILE_NOMATCH    We could not connect to the server.
  1009.  *    FILE_AGAIN    There was a failure in the server, try again
  1010.  *            later.
  1011.  */
  1012. static int
  1013. get_records(qname, qtype, answer, pack_size, error)
  1014.     char *qname;            /* search for this name */
  1015.     int qtype;                /* and for records of this type */
  1016.     register HEADER *answer;        /* buffer for storing answer */
  1017.     int *pack_size;            /* store answer packet size here */
  1018.     char **error;            /* store error message here */
  1019. {
  1020. #ifdef OBSOLETE_RESOLVER
  1021.     char msgbuf[MAXPACKET];
  1022. #endif
  1023.     int msglen;
  1024.     int anslen;
  1025.  
  1026. #ifdef OBSOLETE_RESOLVER
  1027.     msglen = res_mkquery(QUERY, qname, C_IN, qtype, (char *)NULL, 0,
  1028.              (struct rrec *)NULL, msgbuf, MAXPACKET);
  1029.  
  1030.     anslen = res_send(msgbuf, msglen,  (char *)answer, MAXPACKET);
  1031.     if (anslen < 0) {
  1032.     return FILE_NOMATCH;
  1033.     }
  1034. #else /* not OBSOLETE_RESOLVER */
  1035.     anslen = res_search(qname, C_IN, qtype, answer, MAXPACKET);
  1036.     if (anslen < 0) {
  1037.     switch (h_errno) {
  1038.     case NO_DATA:
  1039.         *pack_size = 0;
  1040.         return DB_SUCCEED;
  1041.  
  1042.     case HOST_NOT_FOUND:
  1043.         return DB_NOMATCH;
  1044.  
  1045.     case TRY_AGAIN:
  1046.         *error = "Nameserver: Server failure";
  1047.         return DB_AGAIN;
  1048.  
  1049.     case NO_RECOVERY:
  1050.         *error = "Irrecoverable nameserver error";
  1051.         return FILE_NOMATCH;
  1052.  
  1053.     default:
  1054.         *error = "Unknown nameserver error";
  1055.         return FILE_NOMATCH;
  1056.     }
  1057.     }
  1058. #endif /* not OBSOLETE_RESOLVER */
  1059.     *pack_size = anslen;
  1060.  
  1061.     answer->qdcount = ntohs(answer->qdcount);
  1062.     answer->ancount = ntohs(answer->ancount);
  1063.     answer->nscount = ntohs(answer->nscount);
  1064.     answer->arcount = ntohs(answer->arcount);
  1065.  
  1066.     switch (answer->rcode) {
  1067.  
  1068.     case NOERROR:
  1069.     return DB_SUCCEED;
  1070. #ifdef OBSOLETE_RESOLVER
  1071.     case FORMERR:
  1072.     *error = "Nameserver: Format error in packet";
  1073.     return DB_FAIL;
  1074.  
  1075.     case SERVFAIL:
  1076.     *error = "Nameserver: Server failure";
  1077.     return DB_AGAIN;
  1078.  
  1079.     case NXDOMAIN:
  1080.     return DB_NOMATCH;
  1081.  
  1082.     case NOTIMP:
  1083.     *error = "Nameserver: Unimplemented request";
  1084.     return DB_FAIL;
  1085.  
  1086.     case REFUSED:
  1087.     *error = "Nameserver: Query refused";
  1088.     return FILE_AGAIN;
  1089. #endif /* OBSOLETE_RESOLVER */
  1090.     default:
  1091.     *error = "Nameserver: Unknown response code";
  1092.     return DB_FAIL;
  1093.     }
  1094. }
  1095.  
  1096. /*
  1097.  * getnextrr - get a sequence of resource records from a name server
  1098.  *           response packet.
  1099.  *
  1100.  * The first time getnextrr() is called to process a packet, pass it
  1101.  * the header address of the packet.  For subsequent calls pass NULL.
  1102.  * When no more records remain, getnexrr() returns NULL.
  1103.  *
  1104.  * To process a specific response section, pass the section in sect.
  1105.  */
  1106. static RR *
  1107. getnextrr(it, additional)
  1108.     register struct rr_iterator *it;    /* iteration variables */
  1109.     int additional;        /* interested in additional section RRs */
  1110. {
  1111.     int dnamelen;
  1112.     register unsigned char *dp;
  1113.  
  1114.     dp = (unsigned char *)it->dp;
  1115.  
  1116.     /* return NULL if no rr's remain */
  1117.     if (it->ancount != 0) {
  1118.     --it->ancount;
  1119.     it->rr.rr_sect = SECT_AN;
  1120.     } else if (additional && it->nscount != 0) {
  1121.     --it->nscount;
  1122.     it->rr.rr_sect = SECT_NS;
  1123.     } else if (additional && it->arcount != 0) {
  1124.     --it->arcount;
  1125.     it->rr.rr_sect = SECT_AR;
  1126.     } else {
  1127.     return NULL;
  1128.     }
  1129.  
  1130.     dnamelen = dn_expand((char *)it->hp, it->eom, dp, it->dname, MAXDNAME);
  1131.     if (dnamelen < 0) {
  1132.     return NULL;
  1133.     }
  1134.     dp += dnamelen;
  1135.     GETSHORT(it->rr.rr_type, dp);    /* extract type from record */
  1136.     GETSHORT(it->rr.rr_class, dp);    /* extract class */
  1137.     dp += 4;                /* skip time to live */
  1138.     GETSHORT(it->rr.rr_size, dp);    /* extract length of data */
  1139.     it->rr.rr_data = (char *)dp;    /* there is the data */
  1140.     it->dp = (char *)(dp + it->rr.rr_size); /* skip to next resource record */
  1141.  
  1142.     return &it->rr;
  1143. }
  1144.  
  1145. static void
  1146. rewindrr(it, hp, packsize)
  1147.     register struct rr_iterator *it;
  1148.     HEADER *hp;
  1149.     int packsize;
  1150. {
  1151.     int dnamelen;
  1152.     int qdcount;
  1153.  
  1154.     it->dp = (char *)(hp + 1);
  1155.     it->hp = hp;
  1156.     it->eom = (char *)hp + packsize;
  1157.     it->rr.rr_dname = it->dname;
  1158.     it->ancount = it->hp->ancount;
  1159.     it->nscount = it->hp->nscount;
  1160.     it->arcount = it->hp->arcount;
  1161.     qdcount = it->hp->qdcount;
  1162.     /* skip over questions */
  1163.     while (qdcount > 0) {
  1164.     dnamelen = dn_expand((char *)it->hp, it->eom, it->dp,
  1165.                  it->dname, MAXDNAME);
  1166.     if (dnamelen < 0) {
  1167.         it->ancount = it->nscount = it->arcount = 0;
  1168.     }
  1169.     it->dp += dnamelen;
  1170.     it->dp += 4;            /* skip over class and type */
  1171.     --qdcount;
  1172.     }
  1173. }
  1174.  
  1175.  
  1176. /*
  1177.  * find_a_records - look for an A record for the target
  1178.  *
  1179.  * Look for an A record for the target, and return an appropriate
  1180.  * response code:
  1181.  *
  1182.  *    DB_SUCCEED    An A record was found for the target.
  1183.  *    DB_NOMATCH    There was not an A record.
  1184.  *    DB_FAIL        There was a server error for this query.
  1185.  *    DB_AGAIN    There was a server error for this query, try
  1186.  *            again later.
  1187.  *    FILE_AGAIN    Server error, try again later.
  1188.  *    FILE_NOMATCH    Could not connect to server.
  1189.  *
  1190.  * For response codes other than DB_SUCCEED and DB_NOMATCH, store an
  1191.  * error message.
  1192.  */
  1193. static int
  1194. find_a_records(mx_hint, target, error)
  1195.     struct mx_transport_hint * mx_hint;
  1196.     char *target;
  1197.     char **error;
  1198. {
  1199.     int success;
  1200.     HEADER *a_rrs;
  1201.     int a_size;
  1202.     struct rr_iterator a_it;
  1203.     RR *a_rr;
  1204.     int result = DB_NOMATCH;
  1205.  
  1206.     a_rrs = (HEADER *)xmalloc(MAXPACKET);
  1207.     success = get_records(target, T_A, a_rrs, &a_size, error);
  1208.  
  1209.     if (success != DB_SUCCEED) {
  1210.     xfree((char *)a_rrs);
  1211.     return success;
  1212.     }
  1213.  
  1214.     rewindrr(&a_it, a_rrs, a_size);
  1215.     while ((a_rr = getnextrr(&a_it, FALSE))!=0) {
  1216.     if (a_rr->rr_type == T_A) {
  1217.         result = DB_SUCCEED;
  1218.         add_a_hint(mx_hint, a_it.dname, a_rr->rr_data);
  1219.     }
  1220.     }
  1221.     xfree((char *)a_rrs);
  1222.     return result;
  1223. }
  1224.  
  1225. static int
  1226. decode_mx_rr(rr, it, name, precedence)
  1227.     RR *rr;
  1228.     struct rr_iterator *it;
  1229.     char **name;
  1230.     int *precedence;
  1231. {
  1232.     static char nambuf[MAXDNAME];
  1233.     unsigned char *s = (unsigned char *)rr->rr_data;
  1234.     int dlen;
  1235.  
  1236.     GETSHORT(*precedence, s);
  1237.     dlen = dn_expand((char *)it->hp, it->eom, s, nambuf, MAXDNAME);
  1238.     if (dlen < 0) {
  1239.     return DB_FAIL;
  1240.     }
  1241.     *name = nambuf;
  1242.     return DB_SUCCEED;
  1243. }
  1244.  
  1245.  
  1246. /*
  1247.  * Create error structures for various errors.
  1248.  */
  1249.  
  1250. static struct error *
  1251. lost_server(what)
  1252.     char *what;
  1253. {
  1254.     char *error_text;
  1255.  
  1256.     /*
  1257.      * ERR_163 - lost connection to BIND server
  1258.      *
  1259.      * DESCRIPTION
  1260.      *        Lost connection to the nameserver.
  1261.      *
  1262.      * ACTIONS
  1263.      *      Try again later.
  1264.      *
  1265.      * RESOLUTION
  1266.      *        Hopefully, a later retry will reconnect.
  1267.      */
  1268.     error_text = xprintf("%s: Lost connection to BIND server: %s",
  1269.              what, strerrno());
  1270.     DEBUG1(DBG_DRIVER_LO, "%s\n", error_text);
  1271.  
  1272.     return note_error(ERR_163, error_text);
  1273. }
  1274.  
  1275. static struct error *
  1276. server_failure(what, error)
  1277.     char *what;
  1278.     char *error;            /* additional error text */
  1279. {
  1280.     char *error_text;
  1281.  
  1282.     /*
  1283.      * ERR_164 - failure talking to BIND server
  1284.      *
  1285.      * DESCRIPTION
  1286.      *      An error occured when sending or receiving packets from
  1287.      *        the BIND server, or the server registered an error in the
  1288.      *        response packet.
  1289.      *
  1290.      * ACTIONS
  1291.      *        Actions depend upon the specific error.  Usually, a retry
  1292.      *        is attempted later.
  1293.      *
  1294.      * RESOLUTION
  1295.      *        Resolution depends upon the specific error.
  1296.      */
  1297.     error_text = xprintf("%s: BIND server failure: %s: %s",
  1298.              what, error, strerrno());
  1299.     DEBUG1(DBG_DRIVER_LO, "%s\n", error_text);
  1300.  
  1301.     return note_error(ERR_NPOSTMAST | ERR_164, error_text);
  1302. }
  1303.  
  1304. static struct error *
  1305. packet_error(what, type, host)
  1306.     char *what;
  1307.     char *type;                /* type name of packet */
  1308.     char *host;                /* target host */
  1309. {
  1310.     char *error_text;
  1311.  
  1312.     /*
  1313.      * ERR_165 - response packet format error
  1314.      *
  1315.      * DESCRIPTION
  1316.      *        A format error was found in a packet returned by the BIND
  1317.      *        name server.
  1318.      *
  1319.      * ACTIONS
  1320.      *        Retry again later, in the hope that the problem will go
  1321.      *        away.
  1322.      *
  1323.      * RESOLUTION
  1324.      *        This is probably a bug in the nameserver.
  1325.      */
  1326.     error_text =
  1327.     xprintf("%s: BIND server format error in %s packet for %s",
  1328.         what, type, host);
  1329.     DEBUG1(DBG_DRIVER_LO, "%s\n", error_text);
  1330.  
  1331.     return note_error(ERR_165, error_text);
  1332. }
  1333.  
  1334. static struct error *
  1335. no_valid_mx_records(what, host)
  1336.     char *what;
  1337.     char *host;                /* target hostname */
  1338. {
  1339.     char *error_text;
  1340.  
  1341.     /*
  1342.      * ERR_168 - no valid MX records for host
  1343.      *
  1344.      * DESCRIPTION
  1345.      *        There were MX records for the target host, though all of
  1346.      *        them were rejected.
  1347.      *
  1348.      * ACTIONS
  1349.      *        Delivery to the target fails.
  1350.      *
  1351.      * RESOLUTION
  1352.      *        The postmaster should look into the problem.
  1353.      */
  1354.     error_text = xprintf("%s: no valid MX records for %s",
  1355.              what, host);
  1356.     DEBUG1(DBG_DRIVER_LO, "%s\n", error_text);
  1357.  
  1358.     return note_error(ERR_NSOWNER | ERR_168, error_text);
  1359. }
  1360.  
  1361. static struct error *
  1362. matched_local_host(what, host)
  1363.     char *what;
  1364.     char *host;                /* target hostname */
  1365. {
  1366.     char *error_text;
  1367.  
  1368.     /*
  1369.      * ERR_169 - MX record points to local host
  1370.      *
  1371.      * DESCRIPTION
  1372.      *        The MX record for the target host points to the local
  1373.      *        host, but the local host is not prepared to handle this
  1374.      *        case.
  1375.      *
  1376.      * ACTIONS
  1377.      *        The domain database should probably be looked at.
  1378.      *
  1379.      * RESOLUTION
  1380.      *        The postmaster should probably look into the problem.
  1381.      */
  1382.     error_text = xprintf("%s: MX record for %s points to local host",
  1383.              what, host);
  1384.     DEBUG1(DBG_DRIVER_LO, "%s\n", error_text);
  1385.  
  1386.     return note_error(ERR_NSOWNER | ERR_169, error_text);
  1387. }
  1388.  
  1389. static struct error *
  1390. no_transport_error(what, transport)
  1391.     char *what;
  1392.     char *transport;            /* name of missing transport */
  1393. {
  1394.     char *error_text;
  1395.  
  1396.     /*
  1397.      * ERR_110 - no transport for router
  1398.      *
  1399.      * DESCRIPTION
  1400.      *        A format error was found in a packet returned by the BIND
  1401.      *        name server.
  1402.      *
  1403.      * ACTIONS
  1404.      *        Defer delivery.
  1405.      *
  1406.      * RESOLUTION
  1407.      *        This is a configuration bug.
  1408.      */
  1409.     error_text =
  1410.     xprintf("%s: no such transport %s", what, transport);
  1411.     DEBUG1(DBG_DRIVER_LO, "%s\n", error_text);
  1412.  
  1413.     return note_error(ERR_CONFERR | ERR_110, error_text);
  1414. }
  1415.  
  1416. static struct transport_hints *
  1417. new_mx_hint(pref, dname, implicit)
  1418.     int pref;
  1419.     char * dname;
  1420.     int implicit;
  1421. {
  1422.     struct transport_hints * new_hint;
  1423.     struct mx_transport_hint * mx_hint;
  1424.  
  1425.     new_hint = (struct transport_hints *) xmalloc(sizeof(*new_hint));
  1426.     mx_hint = (struct mx_transport_hint *) xmalloc(sizeof(*mx_hint));
  1427.     new_hint->succ = (struct transport_hints *) 0;
  1428.     new_hint->hint_name = "mx";
  1429.     new_hint->private = (char *) mx_hint;
  1430.     mx_hint->preference = pref;
  1431.     mx_hint->exchanger = dname;
  1432.     mx_hint->implicit = implicit;
  1433.     mx_hint->ipaddrs = (struct ipaddr_hint *) 0;
  1434.     return new_hint;
  1435. }
  1436.  
  1437. static void
  1438. add_mx_hint(addr, precedence, name, implicit)
  1439.     struct transport_hints ** addr;
  1440.     int precedence;
  1441.     char * name;
  1442.     int implicit;
  1443. {
  1444.     struct transport_hints * new_hint;
  1445.  
  1446.     new_hint = new_mx_hint(precedence, COPY_STRING(name), implicit);
  1447. #define mxhint(hint) ((struct mx_transport_hint *)((hint)->private))
  1448.     while (*addr && (! EQ("mx",(*addr)->hint_name)
  1449.              || mxhint(*addr)->preference < precedence))
  1450.     {
  1451.     addr = &(*addr)->succ;
  1452.     }
  1453. #undef mxhint
  1454.     new_hint->succ = *addr;
  1455.     *addr = new_hint;
  1456. }
  1457.  
  1458. static void
  1459. add_a_hint(mx_hint, hostname, address)
  1460.     struct mx_transport_hint *mx_hint;
  1461.     char *hostname;
  1462.     char *address;
  1463. {
  1464.     struct ipaddr_hint * a_hint, ** ah;
  1465.  
  1466.     a_hint = (struct ipaddr_hint *) xmalloc(sizeof(*a_hint));
  1467.     a_hint->succ = NULL;
  1468.     a_hint->hostname = COPY_STRING(hostname);
  1469.     memcpy(&a_hint->addr, address, sizeof(a_hint->addr));
  1470.  
  1471.     ah = &mx_hint->ipaddrs;
  1472.     while (*ah) {
  1473.     ah = &(*ah)->succ;
  1474.     }
  1475.     (*ah) = a_hint;
  1476. }
  1477.  
  1478. static void
  1479. free_mx_hint(hint_p)
  1480.     struct transport_hints ** hint_p;
  1481. {
  1482.     struct transport_hints * next = (*hint_p)->succ;
  1483.     struct ipaddr_hint * addr, * next_addr;
  1484.  
  1485. #define mxhint ((struct mx_transport_hint *)((*hint_p)->private))
  1486.     for (addr = mxhint->ipaddrs; addr; addr = next_addr) {
  1487.     next_addr = addr->succ;
  1488.     xfree(addr->hostname);
  1489.     xfree((char *)addr);
  1490.     }
  1491.     xfree(mxhint->exchanger);
  1492.     xfree((char *)mxhint);
  1493. #undef mxhint
  1494.     xfree((char *)*hint_p);
  1495.     *hint_p = next;
  1496. }
  1497.  
  1498. #endif /* HAVE_BIND */
  1499.